
#include <OneButton.h>
#include <GxEPD2_BW.h>
#include <U8g2_for_Adafruit_GFX.h>
#include <stdlib.h>
#include <stdint.h>
#include <ThreeWire.h>
#include <RtcDS1302.h>
#include <TimeLib.h>
#include <NtpClientLib.h>
#include <ESP8266_Seniverse.h>
#include <SimpleTimer.h>

OneButton button33(33, true);
volatile bool SDcard;
volatile int page;
volatile int Mode;
volatile int chooes;
volatile int ZT;
volatile int i;
volatile int P;
volatile long K;
ThreeWire Wire_14_27_12(14, 27, 12);
RtcDS1302<ThreeWire> rtc(Wire_14_27_12);
String TQ[]={"N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"};

int8_t timeZone = 8;
const PROGMEM char *ntpServer = "ntp1.aliyun.com";
Forecast forecast;
WeatherNow weatherNow;
volatile int SX;
volatile int TQGX;
volatile int CSX;
String WB[]={"System", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A"};

OneButton button32(32, true);
OneButton button26(26, true);
SimpleTimer timer;

void attachLongPressStart33() {
  if (page == 2 && Mode == 0) {
    page--;

  }
  if (ZT == 1) {
    Mode = 1;

  } else {
    Mode = 0;

  }
  if (ZT >= 1) {
    (createFileWithContent("Save", Sou(chooes), K));
    ZT = 0;

  }
  chooes = 1;
  SX = 0;
  clearEPD();
  Serial.println("左键长");
}

//墨水屏初始化
GxEPD2_BW<GxEPD2_154_T8, GxEPD2_154_T8::HEIGHT> display(GxEPD2_154_T8(5, 21, 15, 16));
U8G2_FOR_ADAFRUIT_GFX u8g2;

#include <WiFiManager.h>
  WiFiManager wm;
  bool res;
#include "SdFat.h"
#include <string.h>
extern SdFs sd;
SdFat SD;
SdFat sd;
SdFile myFile;
void attachLongPressStart32() {
  if (page == 1) {
    page++;

  }
  if (ZT == 0) {
    ZT = 2;

  }
  SX = 0;
  Serial.println("右键长");
}

void attachClick26() {
  if (Mode == 1 && ZT == 0) {
    ZT = 1;
    K = RadeSave("Save", Sou(chooes));

  }
  if (page == 2 && Mode == 0) {
    Mode = chooes;

  }
  i = 1;
  P = 0;
  clearEPD();
  SX = 0;
  Serial.println("中键短");
}

void attachClick32() {
  if (((page == 2 && chooes < 5) && Mode == 0) && ZT == 0) {
    chooes++;

  }
  if (Mode == 1 && ZT == 0) {
    chooes++;
    i = 1;
    P = 0;

  }
  if (ZT == 1) {
    K = K + 1;

  }
  clearEPD();
  SX = 0;
  Serial.println("右键短");
}

void Simple_timer_1() {
  if (page == 1) {
    SX = 0;

  }
}

void attachClick33() {
  if ((page == 2 && chooes > 1) && Mode == 0) {
    chooes--;

  }
  if (Mode == 1 && ZT == 0) {
    chooes--;
    i = 1;
    P = 0;

  }
  if (ZT == 1) {
    K = K - 1;

  }
  clearEPD();
  SX = 0;
  Serial.println("左键短");
}

void Simple_timer_2() {
  TQGX = 0;
}

void attachDuringLongPress32() {
  if (ZT == 2) {
    K = K + 1;

  }
  clearEPD();
  SX = 0;
  Serial.println("右键长中");
  Serial.println(K);
}

char* Sou(int i) {

    static char name[256]; // 静态数组保证返回后内存有效
    name[0] = '\0'; // 初始化为空字符串

    FsFile root = sd.open("/");
    if(!root || !root.isDir()) {
      return name;
    }

    FsFile file;
    int count = 0;
    while((file = root.openNextFile())) { // 修改为直接检查文件是否有效
      if(count++ == i) {
        file.getName(name, sizeof(name));
        file.close();
        break;
      }
      file.close();
    }

    root.close();
    return name;


}

void showCH(int x, int y, char* contest) {
  u8g2.drawUTF8(x, y,contest);
}

char* changetype(uint8_t t) {
      // 分配足够存放3位数字+结束符的空间
      char* fic = (char*)malloc(8 * sizeof(char));
      if (fic == NULL) return NULL;

      // 格式化数字到字符串
      snprintf(fic, 8, "%d", t);

      return fic;

}

char* changetxt(String str) {
  return const_cast<char*>(str.c_str());
}

void clearEPD() {
  display.fillScreen(GxEPD_WHITE); // 填充白色
}

void QSX() {
  display.display(false);
}

long RadeSave(char* path, char* filename) {

      String fullPath = String(path) + "/" + filename;

      if (myFile.open(fullPath.c_str(), O_READ)) {
          String numberStr = "";
          while (myFile.available()) {
              char c = myFile.read();
              if (isDigit(c) || c == '-') {
                  numberStr += c;
              }
          }
          myFile.close();

          if (numberStr.length() > 0) {
              int value = numberStr.toInt();
              Serial.println("Integer read: " + String(value) + " from " + fullPath);
              return value;
          }
      }

      Serial.println("Failed to read integer from: " + fullPath);
      return 0;

}

bool createFileWithContent(char* path, char* filename, int value) {
   {
      // 构建完整文件路径
      String fullPath = String(path);
      if (!fullPath.endsWith("/")) {
          fullPath += "/";
      }
      fullPath += filename;

      // 先创建目录（如果不存在）
      if (!sd.exists(path)) {
          if (!sd.mkdir(path)) {
              Serial.print("Failed to create directory: ");
              Serial.println(path);
              return false;
          }
          Serial.print("Directory created: ");
          Serial.println(path);
      }

      // 在指定路径创建文件并写入整数
      if (myFile.open(fullPath.c_str(), O_RDWR | O_CREAT | O_TRUNC)) {
          myFile.println(value);
          myFile.close();
          Serial.print("File created with value: ");
          Serial.print(fullPath);
          Serial.print(" -> ");
          Serial.println(value);
          return true;
      } else {
          Serial.print("Failed to create file: ");
          Serial.println(fullPath);
          return false;
      }
  }
}

char* opnetxt(String name, int K, int L) {
  // 使用静态缓冲区避免动态内存分配
      static char txt[2048];
      const size_t BUFFER_SIZE = sizeof(txt) - 1; // 保留结束符位置
      txt[0] = '\0';

      // 参数验证
      if (K < 1 || L <= 0) return txt;

      FsFile file = sd.open(name);
      if (!file || file.isDirectory()) {
          file.close();
          return txt;
      }

      // 流式处理UTF-8字符
      int charCounter = 0;
      int bytesCopied = 0;
      uint8_t charBytes = 0;
      uint8_t bytePos = 0;

      while (file.available() && charCounter < K + L - 1) {
          uint8_t c = file.read();

          // UTF-8字符处理
          if (charBytes == 0) {
              // 判断新字符长度
              if (c < 0x80) charBytes = 1;
              else if ((c & 0xE0) == 0xC0) charBytes = 2;
              else if ((c & 0xF0) == 0xE0) charBytes = 3;
              else if ((c & 0xF8) == 0xF0) charBytes = 4;
              else charBytes = 1; // 无效UTF-8作为单字节处理

              bytePos = 1;
          } else {
              bytePos++;
          }

          // 当字符计数器进入目标范围时复制
          if (charCounter >= K - 1 && bytesCopied < BUFFER_SIZE) {
              txt[bytesCopied++] = c;
          }

          // 当前字符读取完成
          if (bytePos >= charBytes) {
              charCounter++;
              charBytes = 0;
          }
      }

      // 确保缓冲区截断正确
      if (bytesCopied < BUFFER_SIZE) {
          txt[bytesCopied] = '\0';
      } else {
          txt[BUFFER_SIZE] = '\0';
      }

      file.close();
      return txt;

}

void JSX(int x, int y, int w, int h) {
  display.setPartialWindow(x, y, w, h);
  display.display(true);
}

void SX2() {
  if (ZT == 0) {
      if (CSX == 10) {
        QSX();
        CSX = 0;

      } else {
        JSX(0, 0, 255, 255);
        CSX++;

      }
      SX = 1;

    }
    if (ZT == 1) {
      if (CSX == 20) {
        QSX();
        CSX = 0;

      } else {
        JSX(0, 0, 255, 255);
        CSX++;

      }
      SX = 1;

    }
}

void Mode0() {
  if (Mode == 0) {
    if (page == 1) {
      if (TQGX == 0 && (weatherNow.update() && forecast.update())) {
        TQ[0] = weatherNow.getWeatherText();
        TQ[1] = weatherNow.getDegree();
        TQ[2] = forecast.getHigh(0);
        TQ[3] = forecast.getLow(0);
        TQ[4] = forecast.getRain(0);
        TQ[5] = forecast.getHumidity(0);
        TQ[6] = forecast.getWindDirection(0);
        TQ[7] = forecast.getWindSpeed(0);
        TQ[8] = forecast.getWindScale(0);
        TQGX = 1;

      }
      u8g2.setFont(u8g2_font_timR24_tf);
      showCH(10, 30, changetype(rtc.GetDateTime().Hour()));
      showCH(50, 30, changetype(rtc.GetDateTime().Minute()));
      showCH(40, 30, ":");
      //设置中文字体字号15
      u8g2.setFont(u8g2_font_wqy15_t_gb2312);
      showCH(95, 15, changetxt(String(rtc.GetDateTime().Month()) + String("月") + String(rtc.GetDateTime().Day()) + String("日")));
      if (rtc.GetDateTime().DayOfWeek() == 0) {
        showCH(95, 32, changetxt("星期天"));

      } else {
        showCH(95, 32, changetxt(String("星期") + String(rtc.GetDateTime().DayOfWeek())));

      }
      display.drawRect(0, 0, 150, 35, GxEPD_BLACK);
      display.drawFastVLine(90, 0, 34, GxEPD_BLACK);
      //设置中文字体字号15
      u8g2.setFont(u8g2_font_wqy12_t_gb2312);
      showCH(2, 50, changetxt(String("当前天气：") + String(TQ[0])));
      showCH(2, 65, changetxt(String("当前温度：") + String(TQ[1]) + String("℃")));
      //设置中文字体字号12
      u8g2.setFont(u8g2_font_wqy12_t_gb2312);
      showCH(0, 80, changetxt(String("↑") + String(TQ[2]) + String("℃")));
      showCH(35, 80, changetxt(String("↓") + String(TQ[3]) + String("℃")));
      showCH(0, 95, changetxt(String("降水概率：") + String(TQ[4]) + String("%")));
      showCH(0, 110, changetxt(String("湿度：") + String(TQ[5]) + String("%")));
      // wifi的状态
      if (WiFi.status() == 3) {
          u8g2.setFont(u8g2_font_open_iconic_all_1x_t);
          u8g2.drawGlyph(135,40+1*8,248);

      }
      if (SDcard == 1) {
          u8g2.setFont(u8g2_font_open_iconic_all_1x_t);
          u8g2.drawGlyph(135,50+1*8,167);

      }
      display.drawFastHLine(90, 17, 60, GxEPD_BLACK);
      display.drawFastHLine(0, 115, 150, GxEPD_BLACK);

    }
    if (page == 2) {
      //设置中文字体字号15
      u8g2.setFont(u8g2_font_wqy15_t_gb2312);
      showCH(10, 50, "阅读");
      showCH(60, 50, "天气");
      showCH(110, 50, "配网");
      //设置中文字体字号12
      u8g2.setFont(u8g2_font_wqy12_t_gb2312);
      showCH(5, 120, "时间校准");
        u8g2.setFont(u8g2_font_open_iconic_all_4x_t);
        u8g2.drawGlyph(10,15+2*8,97);
      //阅读图标
        u8g2.setFont(u8g2_font_open_iconic_all_4x_t);
        u8g2.drawGlyph(60,15+2*8,127);
      //天气图标
      u8g2.setFont(u8g2_font_open_iconic_all_4x_t);
        u8g2.drawGlyph(110,15+2*8,102);
      //配网图标
        u8g2.setFont(u8g2_font_open_iconic_all_4x_t);
        u8g2.drawGlyph(10,70+4*8,123);
      //时钟图标
      switch (chooes) {
       case 1:
        display.drawRoundRect(0, 0, 50, 55, 5, GxEPD_BLACK);
        break;
       case 2:
        display.drawRoundRect(50, 0, 50, 55, 5, GxEPD_BLACK);
        break;
       case 3:
        display.drawRoundRect(100, 0, 50, 55, 5, GxEPD_BLACK);
        break;
       case 4:
        display.drawRoundRect(0, 70, 50, 55, 5, GxEPD_BLACK);
        break;
      }

    }

  }
}

void App() {
  //设置中文字体字号15
  u8g2.setFont(u8g2_font_wqy15_t_gb2312);
  if (Mode == 1) {
      if (ZT == 0) {
        P = 1;
        if (SDcard == 1) {
          while (i <= 6) {
            WB[i] = Sou(i);
            if (i >= 2) {
              showCH(2, P * 20, changetxt(WB[i]));

            }
            i++;
            P++;
          }
          if (chooes == 1) {
            chooes = 2;

          }
          switch (chooes) {
           case 1:
            break;
           case 2:
            display.drawFastHLine(0, 42, 100, GxEPD_BLACK);
            break;
           case 3:
            display.drawFastHLine(0, 62, 100, GxEPD_BLACK);
            break;
           case 4:
            display.drawFastHLine(0, 82, 100, GxEPD_BLACK);
            break;
           case 5:
            display.drawFastHLine(0, 102, 100, GxEPD_BLACK);
            break;
           case 6:
            display.drawFastHLine(0, 122, 100, GxEPD_BLACK);
            break;
           case 7:
            display.drawFastHLine(0, 142, 100, GxEPD_BLACK);
            break;
          }

        } else {
          showCH(10, 50, "TF卡读取失败");
          showCH(10, 70, "请在断电后插入TF卡");
          showCH(10, 90, "插入TF卡后重启设备");

        }
        showCH(30, 18, "仅支持UTF-8编码");
        u8g2.setFont(u8g2_font_open_iconic_all_2x_t);
          u8g2.drawGlyph(5,10+1*8,171);
        display.drawFastHLine(0, 25, 255, GxEPD_BLACK);

      }
      if (ZT == 1) {
        clearEPD();
        display.drawFastHLine(0, 15, 255, GxEPD_BLACK);
        showCH(58, 12, changetxt(String(rtc.GetDateTime().Hour()) + String(":") + String(rtc.GetDateTime().Minute())));
        showCH(2, 12, changetype(K));
        if (K != 0) {
          showCH(2, 30, opnetxt(Sou(chooes), K * 70, 10));

        } else {
          showCH(2, 30, opnetxt(Sou(chooes), 1, 9));

        }
        showCH(2, 50, opnetxt(Sou(chooes), K * 70 + 10, 10));
        showCH(2, 70, opnetxt(Sou(chooes), K * 70 + 20, 10));
        showCH(2, 90, opnetxt(Sou(chooes), K * 70 + 30, 10));
        showCH(2, 110, opnetxt(Sou(chooes), K * 70 + 40, 10));
        showCH(2, 130, opnetxt(Sou(chooes), K * 70 + 50, 10));
        showCH(2, 150, opnetxt(Sou(chooes), K * 70 + 60, 10));
        Serial.println("阅读");
        SX2();
        P++;
        if (P >= 11) {
          (createFileWithContent("Save", Sou(chooes), K));
          P = 1;

        }

      }
      if (ZT == 2) {
        clearEPD();
        //设置中文字体字号15
        u8g2.setFont(u8g2_font_wqy12_t_gb2312);
        showCH(20, 20, "阅读进度调整");
        showCH(2, 40, changetxt(String("当前页数：") + String(K)));

      }

    }
    if (Mode == 2) {
      //设置中文字体字号15
      u8g2.setFont(u8g2_font_wqy15_t_gb2312);
      showCH(10, 20, changetxt(String("风向") + String(TQ[6])));
      showCH(10, 40, changetxt(String("风速") + String(TQ[7])));
      showCH(10, 60, changetxt(String("风力等级") + String(TQ[8])));

    }
    if (Mode == 3) {
      //设置中文字体字号12
      u8g2.setFont(u8g2_font_wqy12_t_gb2312);
      showCH(5, 20, "请连接网络进行配网");
      showCH(5, 40, "连接后使用浏览器访问");
      showCH(5, 60, "192.168.4.1");
      showCH(5, 90, "（配网结束后可以长按返回）");
      showCH(5, 105, "若密码输入错误导致设备卡死");
      showCH(5, 120, "请重启设备");
      //刷新界面
      display.nextPage();
      // 一键配网（请让其只执行一次）
      wm.setEnableConfigPortal(1);
      wm.resetSettings();
      wm.setConnectTimeout(5);  // 给30秒尝试连接已知网络
      wm.setConfigPortalTimeout(180); // 几乎不开放配置门户
      wm.autoConnect("电子书");  // 执行自动连接


    }
    if (Mode == 4) {
      // wifi的状态
      if (WiFi.status() == 3) {
        while (NTP.getDateYear() == 1970) {
          delay(500);
        }
        //设置中文字体字号12
        u8g2.setFont(u8g2_font_wqy12_t_gb2312);
        rtc.SetDateTime(RtcDateTime(NTP.getDateYear(), NTP.getDateMonth(), NTP.getDateDay(), NTP.getTimeHour24(), NTP.getTimeMinute(), NTP.getTimeSecond()));
        showCH(50, 50, "设置成功");

      } else {
        //设置中文字体字号12
        u8g2.setFont(u8g2_font_wqy12_t_gb2312);
        showCH(10, 50, "网络连接失败请联网后重试");

      }
      Mode = 0;

    }
}

void setup() {
  button33.attachLongPressStart(attachLongPressStart33);
  Serial.begin(9600);
  SDcard = 0;
  page = 1;
  Mode = 0;
  chooes = 1;
  ZT = 0;
  i = 1;
  P = 0;
  K = 1;
  rtc.Begin();
  NTP.setInterval (600);
  NTP.setNTPTimeout (1500);
  NTP.begin (ntpServer, timeZone, false);
  forecast.config("Scl5KX2P01aG2qIue", "ip", "c", "zh-Hans");
  weatherNow.config("Scl5KX2P01aG2qIue", "ip", "c", "zh-Hans");
  SX = 0;
  TQGX = 0;
  CSX = 0;
  // 一键配网初始化
  // （调试时请打开串口）
  // sd卡初始化

  //联用初始化
    display.init();
    u8g2.begin(display);
    u8g2.setFontMode(1);
    u8g2.setForegroundColor(GxEPD_BLACK);
    u8g2.setBackgroundColor(GxEPD_WHITE);
    display.setFullWindow();
    display.firstPage();
  pinMode(32, INPUT_PULLUP);
  pinMode(26, INPUT_PULLUP);
  pinMode(34, INPUT_PULLUP);
  // 天气页面更新相关数据
  // 天气页面更新相关数据
  // 天气页面更新相关数据
  // 为0即在文本选择界面为1则已经开始阅读
  // 阅读进度
  SDcard = sd.begin(4,SD_SCK_MHZ(4));;
  //设置中文字体字号15
  u8g2.setFont(u8g2_font_wqy15_t_gb2312);
  wm.setConfigPortalTimeout(0); // 完全禁用配置门户
  wm.setEnableConfigPortal(false);
  wm.setConnectTimeout(10);
  res=wm.autoConnect("电子书联网");
  button32.attachLongPressStart(attachLongPressStart32);
  button26.attachClick(attachClick26);
  button32.attachClick(attachClick32);
  timer.setInterval(60000L, Simple_timer_1);

  button33.attachClick(attachClick33);
  timer.setInterval(600000L, Simple_timer_2);

  button32.attachDuringLongPress(attachDuringLongPress32);
}

void loop() {
  // 左键
  button33.tick();
  // 右键
  button32.tick();


  // 确认
  button26.tick();
  // 右键
  button32.tick();
  // 天气10分钟刷新一次
  timer.run();

  // 左键
  button33.tick();
  // 天气10分钟刷新一次
  timer.run();

  // 右键
  button32.tick();
  if (SX == 0) {
    Mode0();
    App();
    SX2();

  }
  delay(100);

}